package com.flyxiaozhu.erp.core.services;

import com.flyxiaozhu.erp.core.entities.Goods;
import com.flyxiaozhu.erp.core.entities.GoodsAttrName;
import com.flyxiaozhu.erp.core.entities.GoodsSku;
import com.flyxiaozhu.erp.core.libs.Constants;
import com.flyxiaozhu.erp.core.pojos.GoodsTagsPojo;
import com.flyxiaozhu.erp.core.repositories.GoodsAttrNameRepository;
import com.flyxiaozhu.erp.core.repositories.GoodsRepository;
import com.flyxiaozhu.erp.core.repositories.GoodsSkuRepository;
import com.flyxiaozhu.erp.core.repositories.GoodsTagRepository;
import com.flyxiaozhu.erp.core.utils.CollectionUtils;
import org.apache.logging.log4j.util.Strings;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Service;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.util.*;

/**
 * @author flyxiaozhu
 * @date 2019-04-17 0:34
 */
@Service
public class GoodsService {
    @Autowired
    GoodsRepository goodsRepository;
    @Autowired
    GoodsAttrNameRepository goodsAttrNameRepository;
    @Autowired
    GoodsSkuRepository goodsSkuRepository;
    @Autowired
    GoodsTagRepository goodsTagRepository;

    public Goods findById(Long id) {
        Goods goods = goodsRepository.findById(id).orElse(null);
        if (goods == null) {
            return null;
        }

        goods.setAttrs(goodsAttrNameRepository.findByGoodsId(id));
        goods.setGoodsSkus(goodsSkuRepository.findByGoodsId(id));

        return goods;
    }

    /**
     * 商品筛选
     *
     * @param keyword
     * @param categoryIds
     * @param tagIds
     * @param minPrice
     * @param maxPrice
     * @param minStock
     * @param maxStock
     * @param appId
     * @param pageable
     * @return
     */
    public Page<Goods> getList(String keyword,
                               Collection<Long> categoryIds,
                               Collection<Long> tagIds,
                               Long minPrice,
                               Long maxPrice,
                               Long minStock,
                               Long maxStock,
                               Pageable pageable) {
        Specification<Goods> specification = new Specification<Goods>() {
            @Nullable // 值允许为空
            @Override
            public Predicate toPredicate(Root<Goods> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                List<Predicate> predicates = new ArrayList<>();

                // 上架
                predicates.add(cb.equal(root.get("isDeleted"), false));
                predicates.add(cb.equal(root.get("status"), Constants.COMMON_STATUS_NORMAL));

                if (Strings.isNotBlank(keyword)) {
                    predicates.add(cb.like(root.get("name"), "%" + keyword + "%"));
                }

                if (minPrice != -99) {
                    predicates.add(cb.greaterThanOrEqualTo(root.get("sellingPrice"), minPrice));
                }

                if (maxPrice != -99) {
                    predicates.add(cb.lessThanOrEqualTo(root.get("sellingPrice"), maxPrice));
                }

                if (minStock != -99) {
                    predicates.add(cb.greaterThanOrEqualTo(root.get("stock"), minStock));
                }

                if (maxStock != -99) {
                    predicates.add(cb.lessThanOrEqualTo(root.get("stock"), maxStock));
                    predicates.add(cb.equal(root.get("isInfiniteStock"), 0));
                }

                //根据分类筛选
                if (categoryIds != null && categoryIds.size() > 0) {
                    predicates.add(cb.in(root.get("categoryId")).value(categoryIds));
                }

                //根据商品标签筛选
                if (tagIds != null && tagIds.size() > 0) {
                    List<GoodsTagsPojo> pojos = goodsTagRepository.getTagedGoodsByTagsIdIn(tagIds);
                    if (pojos.size() != 0) {
                        List<Long> tagedGoodsIds = CollectionUtils.map(pojos, GoodsTagsPojo::getGoodsId);
                        predicates.add(cb.in(root.get("id")).value(tagedGoodsIds));
                    } else {
                        predicates.add(cb.equal(root.get("id"), 0L));
                    }
                }

                return cb.and((Predicate[]) predicates.toArray(new Predicate[predicates.size()]));
            }
        };

        Page<Goods> list = goodsRepository.findAll(specification, pageable);

        Map<Long, List<GoodsAttrName>> attrNameMap = CollectionUtils.group(goodsAttrNameRepository.findAll(), new CollectionUtils.GroupFilter<GoodsAttrName, Long, GoodsAttrName>() {
            @Override
            public Long getKey(GoodsAttrName source) {
                return source.getGoodsId();
            }

            @Override
            public GoodsAttrName getValue(GoodsAttrName source) {
                return source;
            }
        });
        Map<Long, List<GoodsSku>> skuMap = CollectionUtils.group(goodsSkuRepository.findAll(), new CollectionUtils.GroupFilter<GoodsSku, Long, GoodsSku>() {
            @Override
            public Long getKey(GoodsSku source) {
                return source.getGoodsId();
            }

            @Override
            public GoodsSku getValue(GoodsSku source) {
                return source;
            }
        });

        for (Goods goods : list.getContent()) {
            goods.setAttrs(attrNameMap.get(goods.getId()));
            goods.setGoodsSkus(skuMap.get(goods.getId()));
        }
        return list;
    }
}
